//-----------------------------------------------------------------------
// <copyright file="Modify.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <summary>Modifies a WebSite.</summary>
//-----------------------------------------------------------------------
namespace Microsoft.Sdc.Tasks.Web.WebSite
{
    using System;
    using System.DirectoryServices;
    using Microsoft.Sdc.Tasks.Configuration.Web;
    using Microsoft.Build.Framework;

    /// <summary>
    /// Modifies an existing web site
    /// </summary>
    /// <remarks>
    /// <code><![CDATA[<Web.WebSite.Modify 
    ///     Description="description"
    ///     Path="path"
    ///     AuthFlags="authFlags"
    ///     AppPoolId="appPoolId"
    ///     HttpExpires="httpExpires"
    ///     DirBrowseFlags="dirBrowseFlags"
    ///     DefaultDocs="defaultDocs"
    /// />]]></code>
    /// <para>where:</para>
    /// <para><i>description (Required)</i></para>
    /// <para>Web site description to modify.</para>
    /// <para><i>path </i></para>
    /// <para>Local path to assign as the web root.</para>
    /// <para><i>authFlags</i></para>
    /// <para>Authentication flags to apply to the site.</para>
    /// <para><i>appPoolId</i></para>
    /// <para>Application pool to run the site within (IIS6 only).</para>
    /// <para><i>httpExpires</i></para>
    /// <para>Content expiration in hours</para>
    /// <para><i>dirBrowseFlags</i></para>
    /// <para>Directory browsing flags to apply to the site.</para>
    /// <para><i>DefaultDocs</i></para>
    /// <para>Document names allowed as default document for the site.</para>
    /// <para><i>Identifier [output]</i></para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Test" >
    ///         <Web.WebSite.Modify 
    ///             Description='My  Site'
    ///             Path='$(CurrentFolder)\Solution\Secure'/>
    ///     </Target>
    ///     <Target Name="TestWithDefaultDoc" >
    ///         <Web.WebSite.Modify 
    ///             Description='My  Site'
    ///             Path='$(CurrentFolder)\Solution\Secure'
    ///             DirBrowseFlags="EnableDefaultDoc"
    ///             DefaultDocs="Default.aspx;Default.html;index.html;index.htm" />
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>    
    public class Modify : TaskBase
    {
        private string description;
        private string path;
        private string identifier;
        private string authFlagsFromConfig;
        private string appPoolId;
        private string anonymousUserName;
        private string anonymousPassword;
        private string httpExpires;
        private AuthFlags authFlags = 0;
        private string dirBrowseFlagsFromConfig;
        private DirBrowseFlags dirBrowseFlags;
        private ITaskItem[] defaultDocs;
        private string hostName;
        private string machineName = "localhost";

        /// <summary>
        /// Gets or sets the name of the machine to operate on. Default is localhost
        /// </summary>
        public string MachineName
        {
            get { return this.machineName; }
            set { this.machineName = value; }
        }

        /// <summary>
        /// Gets or sets the name of the machine to modify the website on. Default is localhost
        /// </summary>
        /// <value>The name of the machine.</value>
        public string HostName
        {
            get { return this.hostName; }
            set { this.hostName = value; }
        }

        /// <summary>
        /// Description of web site to apply binding to
        /// </summary>
        /// <value>A valid web site description</value>
        [Required]
        public string Description
        {
            get { return (this.description ?? String.Empty); }
            set { this.description = value; }
        }

        /// <summary>
        /// Root path for the web site
        /// </summary>
        /// <value>Existing directory path</value>
        public string Path
        {
            get { return (this.path ?? String.Empty); }
            set { this.path = value; }
        }

        /// <summary>
        /// Web site identifier
        /// </summary>
        /// <value>Any non-existant web site identifier</value>
        /// <remarks>If this property is not defined a web site identifier will be generated 
        /// on site creation.</remarks>
        [Output]
        public string Identifier
        {
            get { return (this.identifier ?? String.Empty); }
            set { this.identifier = value; }
        }

        /// <summary>
        /// Authentication methods for the site
        /// </summary>
        /// <value>A combination of </value>
        /// <value>NTLM </value>
        /// <value>Anonymous </value>
        /// <value>Basic </value>
        /// <value>Digest</value>
        /// <remarks>If unspecified the site will default to anonymous and NTLM</remarks>
        public string AuthFlags
        {
            get { return (this.authFlagsFromConfig ?? String.Empty); }
            set { this.authFlagsFromConfig = value; }
        }

        /// <summary>
        /// Application Pool Identifier
        /// </summary>
        /// <value>Application pool to run the web site under</value>
        /// <remarks>IIS6 and above only</remarks>
        public string AppPoolId
        {
            get { return (this.appPoolId ?? String.Empty); }
            set { this.appPoolId = value; }
        }

        /// <summary>
        /// Gets or sets the anonymous username.
        /// </summary>
        public string AnonymousUsername
        {
            get { return (this.anonymousUserName ?? String.Empty); }
            set { this.anonymousUserName = value; }
        }

        /// <summary>
        /// Gets or sets the anonymous password.
        /// </summary>
        public string AnonymousPassword
        {
            get { return (this.anonymousPassword ?? String.Empty); }
            set { this.anonymousPassword = value; }
        }

        /// <summary>
        /// Number of hours after which the content needs to be expired
        /// </summary>
        public string HttpExpires
        {
            get { return (this.httpExpires ?? String.Empty); }
            set { this.httpExpires = value; }
        }

        /// <summary>
        /// Directory browsing settings for this site.  Use None alone to clear all flags.
        /// </summary>
        /// <value>A combination of</value>
        /// <value>None</value>
        /// <value>ShowDate</value>
        /// <value>ShowExtension</value>
        /// <value>ShowLongDate</value>
        /// <value>ShowSize</value>
        /// <value>ShowTime</value>
        /// <value>EnableDefaultDoc</value>
        /// <value>EnableDirBrowsing</value>
        public string DirBrowseFlags
        {
            get { return (String.IsNullOrEmpty(this.dirBrowseFlagsFromConfig) ? String.Empty : this.dirBrowseFlagsFromConfig); }
            set { this.dirBrowseFlagsFromConfig = value; }
        }

        /// <summary>
        /// Default documents list.  DirBrowseFlags must have EnableDefaultDoc for this list to be in effect.
        /// </summary>
        /// <value>Semicolon-delimited list of default document names in order of precedence.</value>
        public ITaskItem[] DefaultDocs
        {
            get { return this.defaultDocs; }
            set { this.defaultDocs = value; }
        }

        /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            Log.LogMessage(string.Format("Modifying website: {0} on: {1}", this.Description, this.MachineName));

            // check if the site exists
            if (!Microsoft.Sdc.Tasks.Configuration.Web.WebSite.Exists(this.MachineName, this.Description))
            {
                Log.LogMessage(string.Format("Website: {0} does not exist on: {1}", this.Description, this.MachineName));
                return;
            }

            // get the site identifier
            DirectoryEntry de = new DirectoryEntry("IIS://" + this.MachineName + "/W3SVC");
            foreach (DirectoryEntry o in de.Children)
            {
                if (o.SchemaClassName == "IIsWebServer")
                {
                    if ((string)o.Properties["ServerComment"][0] == this.Description)
                    {
                        this.Identifier = Convert.ToInt32(o.Name).ToString();
                    }
                }
            }

            // load the site
            DirectoryEntry site = new DirectoryEntry("IIS://" + this.MachineName + "/w3svc/" + this.Identifier + "/ROOT");

            // make the changes we need to make
            if (!string.IsNullOrEmpty(System.IO.Path.GetFullPath(this.path)))
            {
                Log.LogMessage(string.Format("Setting Path: {0}", this.Path));
                site.Properties["Path"][0] = this.Path;
            }

            if (!string.IsNullOrEmpty(this.AppPoolId))
            {
                Log.LogMessage(string.Format("Setting AppPoolId: {0}", this.AppPoolId));
                site.Properties["AppPoolId"][0] = this.AppPoolId;
            }

            if (!string.IsNullOrEmpty(this.AuthFlags))
            {
                string[] authFlagsSplit = this.authFlagsFromConfig.Split(' ');
                foreach (string authFlagsSplitItem in authFlagsSplit)
                {
                    object flags = Enum.Parse(typeof(AuthFlags), authFlagsSplitItem, true);
                    this.authFlags = this.authFlags | (AuthFlags)flags;
                }

                Log.LogMessage(string.Format("Setting AuthFlags: {0}", this.authFlags));
                site.Properties["AuthFlags"][0] = this.authFlags;
            }

            if (!string.IsNullOrEmpty(this.AnonymousUsername))
            {
                Log.LogMessage(string.Format("Setting AnonymousUsername: {0}", this.AnonymousUsername));
                site.Properties["AnonymousUserName"][0] = this.AnonymousUsername;
            }

            if (!string.IsNullOrEmpty(this.AnonymousPassword))
            {
                Log.LogMessage("Setting AnonymousPassword");
                site.Properties["AnonymousUserPass"][0] = this.AnonymousPassword;
            }

            if (!string.IsNullOrEmpty(this.HttpExpires))
            {
                int httpExpiresInHours = Convert.ToInt32(this.HttpExpires);
                if (httpExpiresInHours != 0)
                {
                    int httpExpiresInSeconds = httpExpiresInHours * 3600;
                    string httpExpire = String.Format("D, 0x{0:X}", httpExpiresInSeconds);
                    Log.LogMessage(string.Format("Setting HttpExpires: {0}", httpExpire));
                    site.Properties["HttpExpires"][0] = httpExpire;
                }
                else
                {
                    Log.LogMessage("Clearing HttpExpires");
                    site.Properties["HttpExpires"][0] = "0";
                }
            }

            if (!string.IsNullOrEmpty(this.DirBrowseFlags))
            {
                string[] dirBrowseFlagsSplit = this.dirBrowseFlagsFromConfig.Split(' ');
                foreach (string dirBrowseFlagsSplitItem in dirBrowseFlagsSplit)
                {
                    object flags = Enum.Parse(typeof(DirBrowseFlags), dirBrowseFlagsSplitItem, true);
                    this.dirBrowseFlags = this.dirBrowseFlags | (DirBrowseFlags)flags;
                }

                Log.LogMessage(string.Format("Setting DirBrowseFlags: {0}", this.dirBrowseFlags));
                site.Properties["DirBrowseFlags"][0] = this.dirBrowseFlags;
            }

            if (this.DefaultDocs != null && this.DefaultDocs.Length > 0)
            {
                string[] defaultDocuments = Array.ConvertAll<ITaskItem, string>(this.DefaultDocs, new Converter<ITaskItem, string>(delegate(ITaskItem item) { return item.ItemSpec; }));

                Log.LogMessage(string.Format("Setting DefaultDoc: {0}", String.Join(", ", defaultDocuments)));
                site.Properties["DefaultDoc"][0] = String.Join(", ", defaultDocuments);
            }

            site.CommitChanges();
        }
    }
}